#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>
// #include <mutex>
#include "lockGuard.hpp"
const int gDefaultCap = 5;

template <class T>
class BlockQueue
{
    bool isQueueEmpty()
    {
        return _bq.size() == 0;
    }
    bool isQueueFull()
    {
        return _bq.size() == _capacity;
    }

public:
    BlockQueue(int capacity = gDefaultCap) : _capacity(capacity)
    {
        pthread_mutex_init(&_mtx, nullptr);
        pthread_cond_init(&Empty, nullptr);
        pthread_cond_init(&Full, nullptr);
    }
    void push(const T &in)
    {
        // // 加锁
        // pthread_mutex_lock(&_mtx);

        // // 检测是否满足访问条件
        // while (isQueueFull())
        //     pthread_cond_wait(&Full, &_mtx);
        // // 访问临界资源
        // _bq.push(in);
        // // 解锁
        // pthread_mutex_unlock(&_mtx);
        // pthread_cond_signal(&Empty);

        lockGuard lockguard(&_mtx);

        while (isQueueFull())
            pthread_cond_wait(&Full, &_mtx);
        _bq.push(in);
        pthread_cond_signal(&Empty);
    }
    void pop(T *out)
    {
        // pthread_mutex_lock(&_mtx);
        // while(isQueueEmpty()) pthread_cond_wait(&Empty, &_mtx);

        // *out = _bq.front();
        // _bq.pop();

        // pthread_mutex_unlock(&_mtx);
        // pthread_cond_signal(&Full);

        lockGuard lockguard(&_mtx);
        while (isQueueEmpty())
            pthread_cond_wait(&Empty, &_mtx);

        *out = _bq.front();
        _bq.pop();
        pthread_cond_signal(&Full);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mtx);
        pthread_cond_destroy(&Empty);
        pthread_cond_destroy(&Full);
    }

private:
    std::queue<T> _bq;
    int _capacity;
    pthread_mutex_t _mtx;
    pthread_cond_t Empty;
    pthread_cond_t Full;
};